package thimeeeee.Model;

//import thimeeeee.Skeleton;
public class Beast extends MovingElement {
	
    private Game game;

    // a szörny tulajdonságai:
    protected boolean _isTracing;     // nyomkövető
	protected boolean _isReproducing; // szaporodó
	protected boolean _isDiamond;     // gyámánttá préselődő

    int intDirection;                 // a mozgást segítő szám
    private double localTimeStamp;
    private int ReproductionInterval = 30; // ennyi Idle()-önként szaporodik a szörny
    private int ReproductionStep = 0;

    public Beast(Game g){
        //Skeleton.Create("Beast");
        _isDiamond = false;
        _isReproducing = false;
        _isTracing = false;
        gotodirection = Direction.up;
        intDirection = 0;
        game = g;
    }

    public Beast(Game g, boolean tracing, boolean reproducing, boolean diamond)
    {
        //Skeleton.Create("Beast");
        _isDiamond = diamond;
        _isReproducing = reproducing;
        _isTracing = tracing;
        gotodirection = Direction.up;
        intDirection = 0;
        game = g;
    }

    // ezek a függvények valósítják meg a tulajdonságokat:
    // a szaporodás folyamata:
	public void Reproduce()
    {
        ReproductionStep = 0;
        
        Direction prevDir = Direction.none;
        // arra a mezőre tesszük a másolatot, ahonnan jöttünk
        switch(gotodirection)
        {
            case up:
                prevDir = Direction.down;
                break;
            case down:
                prevDir = Direction.up;
                break;
            case upleft:
                prevDir = Direction.downright;
                break;
            case upright:
                prevDir = Direction.downleft;
                break;
            case downleft:
                prevDir = Direction.upright;
                break;
            case downright:
                prevDir = Direction.upleft;
                break;
            case none:
                break;
        }

        if(prevDir != Direction.none)
        {
            Field prevField = MyField.GetNeighbor(prevDir);
            // ha létezik a mező, és üres, akkor létrehozzuk az új példányt
            if(prevField != null && prevField.IsEmpty())
            {
                Beast newBeast = new Beast(this.game);
                prevField.AddElement(newBeast);
            }
        }
	}
    // a nyomkövető szörny ezen függvény alapján mozog
	public void Trace() 
    {
//        Skeleton.StartFunc("Beast.Trace");

        Field[] neighborFields = MyField.GetNeighbors();

        if(neighborFields != null)
        {
            int traceCurrentValue = 0;
            int directionValue = -1;

            // megkeressük a legerősebb szagú mezőt
            for(int i = 0; i < neighborFields.length; i++)
            {
                int traceTemp = neighborFields[i].GetTrace();
                if(traceTemp > traceCurrentValue)
                {
                    traceCurrentValue = traceTemp;
                    directionValue = i;
                }
            }
            boolean kovet = true;
            // az eredményt átalakítjuk iránnyá
            switch(directionValue)
            {
                case 0:
                    this.gotodirection = Direction.up;
                    break;
                case 1:
                    this.gotodirection = Direction.down;
                    break;
                case 2:
                    this.gotodirection = Direction.upleft;
                    break;
                case 3:
                    this.gotodirection = Direction.upright;
                    break;
                case 4:
                    this.gotodirection = Direction.downleft;
                    break;
                case 5:
                    this.gotodirection = Direction.downright;
                    break;
                // ha egyik sem, az azt jelenti, hogy a szörny nem fogott szagot
                default:
                    // ekkor ugyan úgy mozog, mint a többi szörny
                    kovet = false;
                    beastMove();
                    break;
            }
            if (kovet)
            {
                Field neighborField = MyField.GetNeighbor(gotodirection);
                if (neighborField.IsEmpty())
                {
                    MoveTo(neighborField);
                }
            }
                       
        }

//        Skeleton.EndFunc("Beast.Trace", "void");
	}

    // ha egy szörny nem tud továbbmenni, mert akadályba ütközik, akkor ez a fv
    // megkeresi, hogy merre tud továbbmenni, és beállítja a gotodirection-t a
    // megfelelő irányra, ha egyik irányba sem tud menni, akkor none-ra
	public void WhereDoIGo()
    {
        //0:fent, 1:lent, 2:balfent, 3:jobbfent, 4:ballent, 5:jobblent
        // sorrend: fel, balfel, balle, le, jobble, jobbfel
        Field[] neighborFields = MyField.GetNeighbors();

        if(neighborFields != null)
        {
            int[] order = {0, 2, 4, 1, 5, 3};
            Direction[] dirOrder = 
            {
                Direction.up,
                Direction.down,
                Direction.upleft,
                Direction.upright,
                Direction.downleft,
                Direction.downright
            };
            boolean dirIsSeted = false;
            int temp = intDirection;

            // pozitív irányban végigjárjuk a szomszédos mezőket, hogy hova léphetünk
            // közben vizsgáljuk, hogy létezik-e a mező
            // addig vizsgáljuk a mezőket, amíg meg nem találjuk az első megfelelőt
            // ezt a dirIsSeted flag jelzi
            for(int i = 1; i <= 6 && !dirIsSeted; i++)
            {
                temp = (intDirection + i) % 6;
                if(neighborFields[order[temp]] != null)
                {
                    if(neighborFields[order[temp]].IsEmpty())
                    {
                        this.gotodirection = dirOrder[order[temp]];
                        dirIsSeted = true;
                        intDirection = temp;
                    }

                }
            }
            // ha nem tudunk továbblépni semerre, azaz körül vagyunk véve, akkor
            // az irányt none-ra állítjuk
            if(!dirIsSeted)
            {
                gotodirection = Direction.none;
                intDirection = 0;
            }
        }
	}
    // a környező mezőkre meghívjuk a meetBeast() metódust, azaz ha a szörny közelében
    // játékos van, akkor azt megöli
    private void MeetBeastOnNeighbors()
    {
        //a MeetBeast meghívása a szomszédokon

        Field[] neighborFields = MyField.GetNeighbors();

        if(neighborFields != null)
        {
            ElementBase[] neighborElements;
            // minden környező mezőn elhelyezkedő elemnek jelzi, hogy ott van
            for(int i = 0; i < neighborFields.length;i++)
            {
                if(neighborFields[i] != null)
                {
                    neighborElements = neighborFields[i].GetElements();

                    if(neighborElements != null)
                    {
                        for(int j = 0; j<neighborElements.length;j++)
                        {
                            if(neighborElements[j] != null) neighborElements[j].MeetBeast();
                        }
                    }
                }
            }
        }
    }
    // a szörnyek mozgatása
    public void beastMove()
    {
        // ha idáig egyhelyben állt a szörny,
        if (gotodirection == Direction.none)
        {
            // akkor megnézzük, hogy tudunk-e valamerre továbbmenni
            WhereDoIGo();
        }
        // ha nem none-t kapunk, akkor tudunk, illetve ha eleve mozogtunk,
        // akkor itt lépünk be
        if(gotodirection != Direction.none)
        {
            Field neighborField = MyField.GetNeighbor(gotodirection);
            if(neighborField != null)
            {
                // ha nem üres a mező, ahova lépni akarunk,
                if(!neighborField.IsEmpty())
                {
                    // akkor körülnézünk, hogy merre tudunk továbbmenni
                    WhereDoIGo();
                }
            }

            // ha ez az új irány (vagy az eredetit vizsgáljuk meg mégegyszer)
            // nem none, akkor oda biztosan léphetünk
            if (gotodirection != Direction.none)
            {
                neighborField = MyField.GetNeighbor(gotodirection);
                MoveTo(neighborField);
            }
            //hapedig még mindig none-t kapunk, akkor tényleg be vagyunk zárva
            //ekkor nem lépünk sehova

        }

    }

    @Override
    public void Idle(double aTimeStamp)
    {
        if (aTimeStamp > localTimeStamp)
        {
            localTimeStamp=aTimeStamp;

    //        Skeleton.StartFunc("Beast.Idle()");

            // ha a szörny követő, akkor aszerint kell mozognia
            if (_isTracing)
            {
                Trace();
            }
            else
            {
                beastMove();
            }

            // a szörnyet körülvevő mezők érinkeznek a szörnnyel
            MeetBeastOnNeighbors();

            // ha szaporodunk, akkor adott időnként
            // elhelyezünk egy Beast-et azon a mezőn, ahonnan jöttünk
            if (_isReproducing)
            {
                if(ReproductionStep == ReproductionInterval)
                {
                    Reproduce();
                }
                else
                {
                    ReproductionStep++;
                }

            }
        }
    //        Skeleton.EndFunc("Beast.Idle()","void");

    }

    // ha nekimegy a játékos:
    @Override
    public boolean MeetPlayer(Player p)
    {
//        Skeleton.StartFunc("Beast.MeetPlayer(p)");
        p.Kill();
//        Skeleton.EndFunc("Beast.MeetPlayer(p)","false");
        return false;
    }

    // ha rázuhan egy kő, vagy gyémánt, akkor a szörny meghal
    @Override
    public boolean MeetFallingElement(FallingElement fe)
    {
//        Skeleton.StartFunc("Beast.MeetFallingElement()");

        //ha esik, akkor elemek megsemmisítése
        if (fe._isFalling)
        {
            //a zuhanó elem is megsemmisül
            fe.Kill();
            this.Kill();
        }
        //egyébként csak nem tud rálépni
//        Skeleton.EndFunc("Beast.MeetFallingElement()", "null");
        return false;
    }

    // ha a szörny valami folytán elpusztul:
    // a gyémánttá préselődő szörny miatt kell felülírni
    @Override
    public void Kill()
    {
//        Skeleton.StartFunc("Beast.Kill()");
        super.Kill();
        if(_isDiamond)
        {
            MyField.AddElement(new Diamond(game));
        }
//        Skeleton.EndFunc("Beast.Kill()", "void");
    }
}